package bancosys.tec.rtm.diagnostician;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import bancosys.tec.rtm.diagnostician.exception.DiagnosticianException;
import bancosys.tec.rtm.diagnostician.report.DiagnosticianReportGenerator;

/**
 * Classe que armazena os diagnosticadores para realizar a diagnose de todos de uma vez e posteriormente gerar o relatório com os
 * resultados.
 * 
 * @author Evaristo
 * @version $Id:$ <b>Created on: </b> 23/01/2007
 */
public class DiagnosticianController {

    private List<Diagnostician> diagnosticians;

    private DiagnosticianReportGenerator diagnosticianReportGenerator;

    private static final Logger LOG = Logger.getLogger(DiagnosticianController.class);

    /**
     * Construtor default.
     * 
     * @param diagnosticianReportGenerator DiagnosticianReportGenerator
     */
    public DiagnosticianController(DiagnosticianReportGenerator diagnosticianReportGenerator) {
        this.diagnosticianReportGenerator = diagnosticianReportGenerator;
        this.diagnosticians = new ArrayList<Diagnostician>();
    }

    /**
     * Adiciona um diagnosticador.
     * 
     * @param diagnostician Diagnostician
     */
    public void addDiagnostician(Diagnostician diagnostician) {
        this.diagnosticians.add(diagnostician);
    }

    /**
     * Adiciona uma lista de diagnosticadores.
     * 
     * @param diagnostician Diagnostician
     */
    public void addDiagnosticianList(List<? extends Diagnostician> diagnostician) {
        this.diagnosticians.addAll(diagnostician);
    }

    /**
     * Adiciona um diagnosticador através de seu Class. obs.: um dos construtores do diagnosticador tem que ser necessariamente sem
     * parâmetros para ele ser adicionado por esse método.
     * 
     * @param diagnostician Class
     * @throws DiagnosticianException erro instanciando diagnosticador
     */
    public void addDiagnostician(Class<? extends Diagnostician> diagnostician) throws DiagnosticianException {
        try {
            this.diagnosticians.add(diagnostician.newInstance());
        } catch (InstantiationException e) {
            throw new DiagnosticianException(e);
        } catch (IllegalAccessException e) {
            throw new DiagnosticianException(e);
        }
    }

    /**
     * Gera e escreve um relatório dos diagnósticos no objeto OutputStream que é passado como parametro.
     * 
     * @param outputStream OutputStream
     */
    public void generateReportOfDiagnosticians(OutputStream outputStream) {
        List<DiagnosisBean> reports = new ArrayList<DiagnosisBean>();
        Iterator<Diagnostician> diagnosticiansIterator = this.diagnosticians.iterator();
        while (diagnosticiansIterator.hasNext()) {
            Diagnostician diagnostician = null;
            try {
                diagnostician = diagnosticiansIterator.next();
                reports.add(diagnostician.diagnosis());
            } catch (Throwable e) {
                if (diagnostician != null) {
                    LOG.error("Erro ao realizar uma diagnose no diagnosticador:" + diagnostician.getClass().getName(), e);
                } else {
                    LOG.error("Erro ao realizar uma diagnose em um diagnosticador desconhecido.", e);
                }
            }
        }
        this.diagnosticianReportGenerator.generateReport(outputStream, reports);
    }
}